from django.core.cache import cache
from django.db import models
from jrcmodel.models import MyConstants, CST
from django.forms.models import ModelForm
from django.forms.extras.widgets import SelectDateWidget
from decimal import Decimal, InvalidOperation, DivisionByZero
from pet.models import EuroConvDaily
import datetime
from django import forms
import src.jrchelpers

# Global dictionary of CSTs and Markets
_g_csts = {}
_g_markets = {}

class TrackRecordUploadForm(forms.Form):
    """ Form to upload track records file """
    years = [(0, u"Year")]
    for y in range(2010, 2020):
        years.append((y, y))
    months = [(0, u"Month")]
    for m in range(1, 13):
        months.append((m, m)) 
    year = forms.IntegerField(widget = forms.Select(choices = years))
    month = forms.IntegerField(widget = forms.Select(choices = months))
    trackfile = forms.FileField()

class TrackRecord(models.Model):
    
    DIRECTION_CHOICES = (
        (u"L", u"Long (buy)")
        , (u"S", u"Short (sell)")
    )
    
    """ Base class for Track records - Futures and Forex """
    status_id = models.IntegerField(choices = MyConstants.STATUS_CHOICES, default = MyConstants.STATUS_APPROVED)
    date = models.DateField(blank = False)
    cst_id = models.ForeignKey(CST)
    direction = models.CharField(max_length = 2, choices = DIRECTION_CHOICES)
    entry_value = models.DecimalField(max_digits = 10, decimal_places = 5)
    exit_value = models.DecimalField(max_digits = 10, decimal_places = 5)
    settlement_position = models.BooleanField(default = False)

    def status_name(self):
        return MyConstants.get_status_name(self.status_id)

    def direction_name(self):
        s = self.direction
        if self.direction == u"L":
            s = u"Long"
        elif self.direction == u"S":
            s = u"Short"
        elif self.direction == u"B":
            s = u"Both"

        return s
    
    def set_direction(self, direction_name):
        """ Sets direction by its name - Short, Long or Both """
        direction_name = direction_name.lower()
        if direction_name == "short":
            self.direction = u"S"
        if direction_name == "long":
            self.direction = u"L"
        if direction_name == "both":
            self.direction = u"B"

    # Market for CST.market_direction_1
    _market_id = None

    def get_market(self):
        """ Caches Market for multiple getters """
        cache_name = "trackrecord_%d_market" % self.pk
        if not _g_markets.has_key(cache_name):
#            print "Selecting CST by PK #%d and storing in global dictionary as %s" % (self.cst_id.pk, cache_name)
            _g_markets[cache_name] = self.cst_id.market_direction_1.market_id
        return _g_markets[cache_name]

    def get_cst(self):
        return self.cst_id
        """
        Returns CST for current Track record (with cache)
        """
        cache_name = "trackrecord/%d/cst" % self.pk
        if not _g_csts.has_key(cache_name):
            _g_csts[cache_name] = self.cst_id
        return _g_csts[cache_name]

class TrackRecordForex(TrackRecord):
    class Meta:
        db_table = "tracking_trackrecfx"
    fee = models.IntegerField(blank = False)
#    min_mov = models.DecimalField(max_digits = 8, decimal_places = 4)
#    currency_xxx = models.CharField(max_length = 3, choices = MyConstants.CURRENCY_CHOICES, blank = True)
#    currency_yyy = models.CharField(max_length = 3, choices = MyConstants.CURRENCY_CHOICES, blank = True)

    @staticmethod
    def clear_tracks_cache():
        # Clear CSTs and Markets cache
        _g_csts.clear()
        _g_markets.clear()
        TrackRecordForex._tracks_by_month.clear()

    def save(self):
        # TODO: clear cache on update and delete
        # Clear CSTs and Markets cache
        _g_csts.clear()
        _g_markets.clear()
        # Clear Track records which were selected before
        TrackRecordForex._tracks_by_month.clear()
        super(TrackRecordForex, self).save()

    def get_currency_xxx(self):
        """
        Returns XXX currency by market direction 1
        """
        market = self.get_market()
        print "Market for currency XXX is: %s" % market
        # TODO: some checking for valid currency
        return market.name[:3]

    def get_currency_yyy(self):
        """
        Returns XXX currency by market direction 1
        """
        market = self.get_market()
        print "Market for currency YYY is: %s" % market
        # TODO: some checking for valid currency
        return market.name[3:]

    def get_min_mov(self):
        return self.get_market().point_price

    def get_profit_losses_pips(self):
        try:
            min_mov = self.get_market().point_price
            print "Min moves (price of 1 point of market %s is %f" % (self.get_market().name, self.get_market().point_price)
            if self.direction == "L":
                return (self.exit_value - self.entry_value) / min_mov
            return (self.entry_value - self.exit_value) / min_mov
        except (InvalidOperation, DivisionByZero):
            return 0
    
    def get_pl_pips_f(self):
        return self.get_profit_losses_pips() - self.fee
    
    _currency_xxx = None
    def get_eurxxx(self):
        if self._currency_xxx == None:
            self._currency_xxx = self.cst_id.market_direction_1.market_id.currency_code

#        print "EUR XXX is: %s" % self._currency_xxx
        if self._currency_xxx == "EUR":
            return 1
        
        ec = EuroConvDaily.objects.get(date = "%d-%d-%d" % (self.date.year, self.date.month, self.date.day))
        if ec == None:
            return "-1"

        if self._currency_xxx == "AUD":
            return ec.EURAUD
        if self._currency_xxx == "CAD":
            return ec.EURCAD
        if self._currency_xxx == "CHF":
            return ec.EURCHF
        if self._currency_xxx == "GBP":
            return ec.EURGBP
        if self._currency_xxx == "JPY":
            return ec.EURJPY
        if self._currency_xxx == "NZD":
            return ec.EURNZD
        if self._currency_xxx == "USD":
            return ec.EURUSD

        return -1
    
    _currency_yyy = None
    def get_euryyy(self):
#        if self._currency_yyy == None:
#            self._currency_yyy = "-"
#            if self.cst_id.market_direction_2 != None:
#                self._currency_yyy = self.cst_id.market_direction_2.market_id.name

        self._currency_yyy = self.get_currency_yyy()
        print "EUR YYY is: %s" % self._currency_yyy
        
        try:
            ec = EuroConvDaily.objects.get(date = "%d-%d-%d" % (self.date.year, self.date.month, self.date.day))
        except (EuroConvDaily.DoesNotExist, EuroConvDaily.MultipleObjectsReturned):
            print "EuroConvDaily not found or duplicated for date %d-%d-%d!" % (self.date.year, self.date.month, self.date.day)
            return -1

        # Normally we should check only AUD, CAD, CHF, etc. But this is just in case :)
        if self._currency_yyy == "AUD" or self._currency_yyy == "EURAUD":
            return ec.EURAUD
        if self._currency_yyy == "CAD" or self._currency_yyy == "EURCAD":
            return ec.EURCAD
        if self._currency_yyy == "CHF" or self._currency_yyy == "EURCHF":
            return ec.EURCHF
        if self._currency_yyy == "GBP" or self._currency_yyy == "EURGBP":
            return ec.EURGBP
        if self._currency_yyy == "JPY" or self._currency_yyy == "EURJPY":
            return ec.EURJPY / 100
        if self._currency_yyy == "NZD" or self._currency_yyy == "EURNZD":
            return ec.EURNZD
        if self._currency_yyy == "USD" or self._currency_yyy == "EURUSD":
            return ec.EURUSD
        
        # Don't know why :( Need to remove!
        if self._currency_yyy == "GBPJPY":
            return ec.EURJPY / 100
        if self._currency_yyy == "USDJPY":
            return ec.EURJPY / 100
        if self._currency_yyy == "AUDJPY":
            return ec.EURJPY / 100
        
        if self.cst_id.name == "NZDUSD-daily":
            return ec.EURUSD
        
#        print "Can't get EURYYY conversion for #%s" % self.cst_id.name
        return -1
        
    def get_plpips_div_euryyy(self):
        euryyy = self.get_euryyy()
        if euryyy == 0:
            return 0
        return self.get_profit_losses_pips() / euryyy
    
    def get_plpips_f_div_euryyy(self):
        euryyy = self.get_euryyy()
        if euryyy == 0:
            return 0
        return self.get_pl_pips_f() / euryyy
    
    
    # Just to cache
    _tracks_by_month = {}
    
    @staticmethod
    def get_tracks_by_month(year, month):
        sdate = "%d-%02d" % (year, month)
        if not TrackRecordForex._tracks_by_month.has_key(sdate):
            next_year = year
            next_month = month + 1
            if next_month > 12:
                next_month = 1
                next_year = year + 1
            TrackRecordForex._tracks_by_month[sdate] = TrackRecordForex.objects.filter(date__gte = "%s-01" % sdate).filter(date__lte = "%d-%02d-01" % (next_year, next_month)).order_by("date", "pk")

        return TrackRecordForex._tracks_by_month[sdate]
    
    @staticmethod
    def calculate_month_stats(year, month):
        """
        Caclulates various data used to display charts and totals
        """
        stats = MonthStatsForex()
        tracks = TrackRecordForex.get_tracks_by_month(year, month)
        
        i = 0
        fees = 0
        pl_acc = Decimal(0)
        pl_pips_acc = Decimal(0)
        pl_pips_f_acc = Decimal(0)
        stats.pl_pips_div_eur_total = Decimal(0)
        stats.pl_pips_f_div_eur_total = Decimal(0)
        stats.fees_total = 0

        # Clear from previous request
        stats.pl_accumulated = []
        stats.pl_pips_f_div_eur = []
        stats.pl_pips_div_eur = []
        stats.pl_pips_accumulated = []
        stats.pl_pips_f_accumulated = []

        for t in tracks:
            cst_name = t.cst_id.name.upper()
            if not stats.markets_totals.has_key(cst_name):
                stats.markets_totals[cst_name] = 0
#            print "%s: %f" % (t.date, t.get_pl_pips_f())
            stats.markets_totals[cst_name] = stats.markets_totals[cst_name] + t.get_pl_pips_f()

            if not stats.markets_pl_pipsf.has_key(cst_name):
                stats.markets_pl_pipsf[cst_name] = 0
            stats.markets_pl_pipsf[cst_name] = stats.markets_pl_pipsf[cst_name] + t.get_pl_pips_f()

#            print "%s. Fee: %d" % (t.date, t.fee)
            fees = fees + t.fee
            stats.fees_accumulated = stats.fees_accumulated + [fees]

            pl_acc = pl_acc + t.get_profit_losses_pips()
            stats.pl_accumulated += [pl_acc]
#            pl_pips_acc = pl_pips_acc + t.get_plpips_div_euryyy()
#            stats.pl_accumulated += [pl_pips_acc]
            
            stats.fees_total = stats.fees_total + t.fee
            stats.pl_pips_total = stats.pl_pips_total + t.get_profit_losses_pips()
            stats.pl_pips_f_total = stats.pl_pips_f_total + t.get_pl_pips_f()
#            print "P/L pips / EUR YYY for %s is: %f" % (t.date, t.get_plpips_div_euryyy())

#            print "%s. P/L (fees): %f" % (t.date, t.get_plpips_f_div_euryyy())
            pl_pips_f_acc += t.get_plpips_f_div_euryyy()
            stats.pl_pips_f_accumulated += [pl_pips_f_acc]

            pl_pips_div_euryyy = t.get_plpips_div_euryyy()
#            print "[%s] P/L pips/EURYYY: %f" % (t.date, pl_pips_div_euryyy)
            stats.pl_pips_div_eur += [pl_pips_div_euryyy]
            stats.pl_pips_f_div_eur += [t.get_plpips_f_div_euryyy()]

            pl_pips_acc += pl_pips_div_euryyy
            stats.pl_pips_accumulated += [pl_pips_acc]
            stats.pl_pips_div_eur_total = stats.pl_pips_div_eur_total + pl_pips_div_euryyy 
            stats.pl_pips_f_div_eur_total = stats.pl_pips_f_div_eur_total + t.get_plpips_f_div_euryyy()

            i += 1

#        print "P/L pips EUR: %s" % stats.pl_pips_div_eur
#        print "P/L pips EUR (fees): %s" % stats.pl_pips_f_div_eur
#        print "Markets PL by CST: %s" % stats.markets_pl_pipsf
#        print "Length of accumulated fees: %d" % len(stats.fees_accumulated)
#        print "Length of accumulated P/L: %d" % len(stats.pl_accumulated)
#        print "Accumulated P/L pips: %s" % stats.pl_pips_accumulated
#        print "Accumulated P/L: %s" % stats.pl_accumulated
#        print "Accumulated P/L (fees): %s" % stats.pl_pips_f_accumulated
#        print "Accumulated fees: %s" % stats.fees_accumulated

        return stats
    
class MonthStatsFutures:
    contracts_qnt_total = 0
    points_total = 0
    profit_losses_fees = []
    profit_losses_total = Decimal(0)
    profit_losses_fees_total = Decimal(0)
    number_of_trades_total = 0
    # Percent => value
    percentiles = []

    def __init__(self):
        # Predefined
        self.percentiles = [0] * 3
        self.percentiles[0] = (0.05, 0)
        self.percentiles[1] = (0.08, 0)
        self.percentiles[2] = (0.09, 0)

        pct = 0.1
        while pct <= 1:
            self.percentiles.append( (pct, 0) )
            pct += 0.05
        sorted(self.percentiles)
#        print "Percentiles: %s" % self.percentiles


    
class MonthStatsForex:
    markets_totals = {}
    fees_accumulated = []
    pl_accumulated = []
    pl_pips_div_eur = []
    pl_pips_f_div_eur = []
    pl_pips_accumulated = []
    pl_pips_f_accumulated = []
    markets_pl_pipsf = {}
    
    fees_total = 0
    pl_pips_total = Decimal(0)
    pl_pips_f_total = Decimal(0)
    pl_pips_div_eur_total = Decimal(0)
    pl_pips_f_div_eur_total = Decimal(0)
    
    def get_markets_names_to_js(self):
        return "[%s]" % "', '".join(self.markets_totals)
    
#    def __unicode__(self):
#        return "#%s" % (self.cst_id.name)

class TrackRecordFutures(TrackRecord):
    
    # Tracks of this date from DB (cache)
    _tracks = None
    
    class Meta:
        db_table = "tracking_trackrec"
    corrected_points = models.BooleanField(default = False)
    contracts_qnt = models.IntegerField(default = 0)
    # to cache value from DB
    one_or_eurusd = None

    def get_point_value(self):
        v = 0
        if self.get_market() != None:
            v = self.get_market().point_price
        return v
    
    def get_currency_symbol(self):
        cc = ""
#        cc = self.cst_id.market_direction_1.market_id.currency_code
        if self.get_market() != None:
            cc = self.get_market().currency_code
        return MyConstants.get_currency_symbol(cc.upper())
    
    def get_trading_profit_losses(self):
        return "N/A"
#        print "Trading P/L: %.4f" % self.trading_profit_losses
#        return self.trading_profit_losses
    
    def get_profit_losses_eur(self):
#        print "get P/L EUR for #%d: 1 or EURUSD: %f, point value: %f, contracts: %d, points: %d" % (self.pk, self.get_1_or_eurusd(), self.get_point_value(), self.contracts_qnt, self.get_points())
        if self.get_1_or_eurusd() == 0 or self.get_1_or_eurusd() is None:
            print "No EUR/USD for TrackRecordFutures #%d" % self.pk
            return 0
        return self.get_point_value() * self.contracts_qnt * self.get_points() / self.get_1_or_eurusd()

    def get_profit_losses_including_fees_eur(self):
        return self.get_profit_losses_eur() - self.contracts_qnt * 30

    def get_1_or_eurusd(self):
        currency_code = ""

        # Check whether currency is EUR and return 1
        if self.get_market() is not None:
            currency_code = self.get_market().currency_code
#        print "Currency code is: %s" % currency_code
        if currency_code == "EUR":
            return 1

        cache_name = "one_or_eurusd/%d-%d-%d" % (self.date.year, self.date.month, self.date.day)
        one_or_eurusd = cache.get(cache_name)
        if one_or_eurusd is not None:
            return one_or_eurusd

        # Check if it is calculated
        if self.one_or_eurusd is not None:
            return self.one_or_eurusd
        
        if currency_code == "EUR":
            self.one_or_eurusd = 1
        else:
            print "Searching for 1 or EURUSD for %d-%d-%d" % (self.date.year, self.date.month, self.date.day)

            sdate = "%d-%d-%d" % (self.date.year, self.date.month, self.date.day)

            try:
                ec = EuroConvDaily.objects.get(date = sdate)
            except EuroConvDaily.MultipleObjectsReturned:
                print "Multiple EUR conversions for date: %s" % sdate
                return None
            except EuroConvDaily.DoesNotExist:
                # No conversion for current date, search for closest occurence
                ec_desired_dt = datetime.date.today()
#                ec_desired_dt = datetime.datetime.strptime(sdate, "%Y-%m-%d")
                print "No EUR conversion for date %s. Let's search for fallback +-1 day" % sdate
                ec_prev = EuroConvDaily.objects.filter(date__lt = sdate)[:1]
                ec_next = EuroConvDaily.objects.filter(date__gt = sdate)[:1]
                
                # Compare diference between previous and next conversion
                if ec_prev.count() == 0 and ec_next.count() == 0:
                    print "Could not find previous/next EUR conversion for date %s" % sdate
                    ec = None
                else:
                    if ec_next.count() == 0:
                        ec = ec_prev[0]
                    else:
                        if ec_prev.count() == 0:
                            ec = ec_next[0]
                        else:
                            print "Total next EUR conversions: %d" % ec_next.count()
                            print "Total previous EUR conversions: %d" % ec_prev.count()
                            if (ec_next[0].date - ec_desired_dt).days < (ec_desired_dt - ec_prev[0].date).days:
                                ec = ec_next[0]
                            else:
                                ec = ec_prev[0]
                if ec != None:
                    print "EUR fallback conversion for date %s is date %s" % (sdate, ec.date)

            if ec is None:
                self.one_or_eurusd = "X"
            if currency_code == "USD":
                # Store in cache for 3 hours
                cache.set(cache_name, ec.EURUSD, 3 * 60 * 60)
                self.one_or_eurusd = ec.EURUSD

        if self.pk == 1973:
            print "Return EUR/USD: %s" % self.one_or_eurusd
        return self.one_or_eurusd
    
    def get_points(self):
        if self.direction == "L":
            return self.exit_value - self.entry_value
        return self.entry_value - self.exit_value
    
    def get_pct(self):
        if self.get_profit_losses_including_fees_eur() == 0:
            return 0
        return self.trading_profit_losses / self.get_profit_losses_including_fees_eur()
    
    def get_current_day_tracks(self):
        """
        Returns Track records from DB using simple cache
        """
        cache_name = "tracking/futures/day/%s" % self.date
        tracks = cache.get(cache_name)
        if tracks is None:
            print "Selecting Track records (Futures) for %s and storing in cache as %s" % (self.date, cache_name)
            tracks = TrackRecordFutures.objects.filter(date = self.date)
            # Store in cache for 1 hour
            cache.set(cache_name, tracks, 60 * 60)
        return tracks

    _current_month_tracks = None
    def get_profit_losses_fees_till_day(self):
        pl_total = 0
        contracts_qnt_total = 0
        start_date = "%d-%d-01" % (self.date.year, self.date.month)

        if self.date.month == 12:
            end_date = "%d-01-01" % (self.date.year + 1)
        else:
            end_date = "%d-%d-01" % (self.date.year, self.date.month+1)

        # Try cache by key
        cache_name = "tracking/futures/tracks_%s-%s" % (start_date, end_date)
        tracks = cache.get(cache_name)
        if tracks is None:
            print "Selecting Track records (Futures) [%s - %s] and storing in cache as %s" % (start_date, end_date, cache_name)
            tracks = TrackRecordFutures.objects.filter(date__gte = start_date).filter(date__lt = end_date)
            # Store in cache for 1 hour
            cache.set(cache_name, tracks, 60 * 60)

        for tr in tracks:
            if tr.date <= self.date:
#                print "%.5f\t%d" % (tr.get_profit_losses_eur(), tr.contracts_qnt)
                pl_total += tr.get_profit_losses_eur()
                contracts_qnt_total += 30 * tr.contracts_qnt
#        print "Total: %.5f\t%d" % (pl_total, contracts_qnt_total)
        
        return pl_total - contracts_qnt_total
    
    def get_profit_losses_fees_for_day(self):
        """
        Returns sum for P/L w/ fees for current day
        """
        total = 0
        
        items = self.get_current_day_tracks()
        # Counting P/L for current day
        for tr in items:
#            print tr.get_profit_losses_eur()
            total += tr.get_profit_losses_eur()
#        print "Total P/L for day %s is %f" % (self.date, total)
#        print "Qnt of contracts for this day is %d, total fees = %d" % (self.get_contracts_for_day(), self.get_contracts_for_day() * 30)
        total -= self.get_contracts_for_day() * 30
        return total
    
    def get_contracts_for_day(self):
        """
        Returns sum of contracts for current day
        """
        total = 0
        
        items = self.get_current_day_tracks()
#        print "Caluclating # of contracts for %s" % self.date
        for tr in items:
#            print "Contracts for %s: %d" % (tr.date, tr.contracts_qnt)
            total += tr.contracts_qnt
        
        return total
    
    # Just to cache
    _tracks_by_month = {}
    
    @staticmethod
    def get_tracks_by_month(year, month):
        sdate = "%d-%02d" % (year, month)
        next_year = year
        next_month = month + 1
        if next_month > 12:
            next_month = 1
            next_year = year + 1

        cache_name = "tracking/futures/tracks/%s" % sdate
        tracks = cache.get(cache_name)
        if tracks is None:
            print "Selecting Track records (Futures) for %s and storing in cache as %s" % (sdate, cache_name)
            tracks = TrackRecordFutures.objects.filter(date__gte = "%s-01" % sdate).filter(date__lte = "%d-%02d-01" % (next_year, next_month)).order_by("date").order_by("pk")
            # Cache for 1 hour
            cache.set(cache_name, tracks, 60 * 60)

        return tracks

    @staticmethod
    def clear_tracks_cache(year, month):
        """
        Clears cached Track records (Futures) for specific month
        """

        # Clear CSTs and Markets cache
        _g_csts.clear()
        _g_markets.clear()

        sdate = "%d-%02d" % (year, month)
        cache_name = "tracking/futures/tracks/%s" % sdate
        cache.delete(cache_name)

#    @staticmethod
    def calculate_month_stats(self, year, month):
        stats = MonthStatsFutures()
        tracks = TrackRecordFutures.get_tracks_by_month(year, month)
        
        # How many days in months
        days_in_months = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        if year % 4 == 0:
            days_in_months[2] = 29

        # Store P/L for whole day
        stats.profit_losses_daily = [0] * (days_in_months[month] + 1)
        stats.profit_losses_fees = []
        # Totals for each market
        stats.markets_totals = {}
        stats.markets_totals_min = 10000000
        stats.markets_totals_max = -10000000
        
        # Store CST_ID => CST_ProfitLosses
        temp_markets_totals = {}
        
        for t in tracks:
            # Dirty solution :(
            if t is None or t.date.year != year or t.date.month != month:
                continue

#            print "%s\t%s" % (t.date, t.get_points())
#            if t.number_of_trades != None:
#                stats.number_of_trades_total = stats.number_of_trades_total + t.number_of_trades
            stats.points_total = stats.points_total + t.get_points()
#            print "P/L for %s is %f" % (t.date, t.get_profit_losses_eur())
            stats.profit_losses_total = stats.profit_losses_total + t.get_profit_losses_eur()
#            print "P/L (fees) for %s is %f" % (t.date, t.get_profit_losses_including_fees_eur())
            v = t.get_profit_losses_including_fees_eur()
            stats.profit_losses_fees.append(v)
            stats.profit_losses_fees_total = stats.profit_losses_fees_total + v

            # Calculate whole day P/L, if it is not calucalted, already
            if stats.profit_losses_daily[t.date.day] == 0:
#                print "P/L for day %s is: %f" % (t.date, t.get_profit_losses_fees_till_day())
                stats.profit_losses_daily[t.date.day] = t.get_profit_losses_fees_till_day()

            name = "{0:d}".format(t.get_cst().pk)
#            name = "%d" % t.cst_id.pk
            if not temp_markets_totals.has_key(name):
                temp_markets_totals[name] = Decimal(0)
            v = t.get_profit_losses_eur()
#            print "Current totals: %s" % temp_markets_totals[name]
#            v += temp_markets_totals[name]
            temp_markets_totals[name] += v
                
            # Contracts are calculate not last day
#            print "Day of Track record: %d of %d days in %d month" % (t.date.day, days_in_months[month], month)
            if t.corrected_points and (days_in_months[month] - t.date.day < 2):
#                print "Skiping %s" % t.date
                continue

            stats.contracts_qnt_total = stats.contracts_qnt_total + t.contracts_qnt
            
        # Prepare good formatted Markets totals
        for pk, pl in temp_markets_totals.iteritems():
            cst = CST.objects.get(pk = pk)
            name = "{0} ({1:,.1f} {2})".format(cst.name, pl, cst.market_direction_1.market_id.currency_code)
            stats.markets_totals[name] = pl
            if stats.markets_totals_max < pl:
                stats.markets_totals_max = pl
            if stats.markets_totals_min > pl:
                stats.markets_totals_min = pl
        # Used for charts
        stats.markets_totals_max += 100
        stats.markets_totals_min -= 100

        # Fill gaps in P/L daily (for holidays)
        prev_pl_daily = 0
        for i in range(1, len(stats.profit_losses_daily)):
            if stats.profit_losses_daily[i] == 0:
                stats.profit_losses_daily[i] = prev_pl_daily
            else:
                prev_pl_daily = stats.profit_losses_daily[i]

#        print "Unsorted profit/losses total: %s" % stats.profit_losses_fees
        # Put P/L w/ fees to array as float (not good)
        ar_profit_losses = []
        for p in stats.profit_losses_fees:
            ar_profit_losses.append(float(p))
        ar_profit_losses = sorted(ar_profit_losses)
#        print "Calculate percentiles for array: %s" % ar_profit_losses
        # Calculate percentile for each percent
        for i in range(0, len(stats.percentiles)):
            kvp = stats.percentiles[i]
#            print "Calculating percentile for %d%%" % (kvp[0] * 100)
            stats.percentiles[i] = (kvp[0], src.jrchelpers.percentile(ar_profit_losses, kvp[0]))

#        print "Calculated percentiles: %s" % stats.percentiles
        print "P/L for each markets: %s" % stats.markets_totals
#        print "P/L accumulated by days: %s" % stats.profit_losses_daily

        return stats
    
    
class MonthYearLinks:
    base_link = "/"
    current_year = 0
    current_month = 0
    
    def get_url_to_next(self):
        if self.current_year == 0 or self.current_month == 0:
            raise Exception("Not-initialized MonthYearLink!")
        if self.current_month > 11:
            return "%s?year=%d&month=01" % (self.base_link, self.current_year + 1)
        return "%s?year=%d&month=%02d" % (self.base_link, self.current_year, self.current_month + 1)

    def get_url_to_prev(self):
        if self.current_year == 0 or self.current_month == 0:
            raise Exception("Not-initialized MonthYearLink!")
        if self.current_month < 2:
            return "%s?year=%d&month=12" % (self.base_link, self.current_year - 1)
        return "%s?year=%d&month=%02d" % (self.base_link, self.current_year, self.current_month - 1)

    def __init__(self, base_link, request = None):
        self.base_link = base_link
        if request != None:
            try:
                self.current_year = int(request.GET.get("year"))
                self.current_month = int(request.GET.get("month"))
            except:
                # Initialize to current year/month
#                print "Error initializing MonthYearLink!"
                self.current_year = datetime.datetime.now().year
                self.current_month = datetime.datetime.now().month


class TrackingWeek:
    year = 2012
    month = 1
    monday = 0
    tuesday = 0
    wednesday = 0
    thursday = 0
    friday = 0
    saturday = 0
    sunday = 0
    
    def __init__(self, year, month, first_week_date = -1, first_day_of_month = -1):
        self.year = year
        self.month = month
    
    def set_for_weekday(self, weekday, value):
        """
        Sets day of month to specific day of week, set_for_weekday(1, 3) => Monday is 3rd
        """
        if weekday == 1:
            self.monday = value
            return
        if weekday == 2:
            self.tuesday = value
            return
        if weekday == 3:
            self.wednesday = value
            return
        if weekday == 4:
            self.thursday = value
            return
        if weekday == 5:
            self.friday = value
            return
        if weekday == 6:
            self.saturday = value
            return
        if weekday == 7:
            self.sunday = value
            return

    def get_weekday(self, weekday):
        """
        Gets date of weekday get_weekday(4) => returns which day of month is Thursday
        """
        if weekday == 1:
            return self.monday
        if weekday == 2:
            return self.tuesday
        if weekday == 3:
            return self.wednesday
        if weekday == 4:
            return self.thursday
        if weekday == 5:
            return self.friday
        if weekday == 6:
            return self.saturday
        if weekday == 7:
            return self.sunday
    
    def get_date_for_weekday(self, weekday):
        try:
#        print "Getting date of %d (weekday)" % weekday
            monthday = self.get_weekday(weekday)
            str_date = "2011-%02d-%02d 22" % (self.month, monthday)
#            print str_date
            if monthday == 0:
                return "XXXX"
            return datetime.datetime.strptime(str_date, "%Y-%m-%d %H")
        except:
            return "Yyyy"
#        if self.monday == 0:
#            return 0
#        return "2011-%02d-%02d" % (self.month, self.monday)
    
    def get_date_for_monday(self):
        return self.get_date_for_weekday(1)
    def get_date_for_tuesday(self):
        return self.get_date_for_weekday(2)
    def get_date_for_wednesday(self):
        return self.get_date_for_weekday(3)
    def get_date_for_thursday(self):
        return self.get_date_for_weekday(4)
    def get_date_for_friday(self):
        return self.get_date_for_weekday(5)
    def get_date_for_saturday(self):
        return self.get_date_for_weekday(6)
    def get_date_for_sunday(self):
        return self.get_date_for_weekday(7)
    
    def get_futures_tracks_for_monday(self):
        return self.get_futures_tracks_for_weekday(1)
    def get_futures_tracks_for_tuesday(self):
        return self.get_futures_tracks_for_weekday(2)
    def get_futures_tracks_for_wednesday(self):
        return self.get_futures_tracks_for_weekday(3)
    def get_futures_tracks_for_thursday(self):
        return self.get_futures_tracks_for_weekday(4)
    def get_futures_tracks_for_friday(self):
        return self.get_futures_tracks_for_weekday(5)
    def get_futures_tracks_for_saturday(self):
        return self.get_futures_tracks_for_weekday(6)
    def get_futures_tracks_for_sunday(self):
        return self.get_futures_tracks_for_weekday(7)
    
    def get_futures_tracks_for_weekday(self, weekday):
        if weekday > 7 or weekday < 1:
            return None
#        print "Weekday is %d, searching for date %s" % (day, "%d-%02d-%02d" % (self.year, self.month, self.get_weekday(day)))
        return TrackRecordFutures.objects.filter(date = "%d-%02d-%02d" % (self.year, self.month, self.get_weekday(weekday)))
        
    def get_forex_tracks_for_monday(self):
        return self.get_forex_tracks_for_weekday(1)
    def get_forex_tracks_for_tuesday(self):
        return self.get_forex_tracks_for_weekday(2)
    def get_forex_tracks_for_wednesday(self):
        return self.get_forex_tracks_for_weekday(3)
    def get_forex_tracks_for_thursday(self):
        return self.get_forex_tracks_for_weekday(4)
    def get_forex_tracks_for_friday(self):
        return self.get_forex_tracks_for_weekday(5)
    def get_forex_tracks_for_saturday(self):
        return self.get_forex_tracks_for_weekday(6)
    def get_forex_tracks_for_sunday(self):
        return self.get_forex_tracks_for_weekday(7)
    
    def get_forex_tracks_for_weekday(self, weekday):
        if weekday > 7 or weekday < 1:
            return None
#        print "Track records (Forex) for date: %d-%02d-%02d" % (self.year, self.month, self.get_weekday(weekday))
        return TrackRecordForex.objects.filter(date = "%d-%02d-%02d" % (self.year, self.month, self.get_weekday(weekday)))
        
#    def __unicode__(self):
    def __str__(self):
        return "Mon: %d, Tue: %d, Wed: %d, Thu: %d, Fri: %d, Sat: %d, Sun: %d" % (self.monday, self.tuesday, self.wednesday, self.thursday, self.friday, self.saturday, self.sunday)


